package com.lz.sports.utils

import android.text.TextUtils
import com.bumptech.glide.Glide
import com.github.mjdev.libaums.fs.UsbFile
import com.github.mjdev.libaums.fs.UsbFileInputStream
import com.lz.library.extension.APP
import com.lz.library.utils.FileUtils
import com.lz.sports.bean.ExamPlan
import com.lz.sports.bean.ExamResult
import com.lz.sports.bean.Examinee
import com.lz.sports.db.ExamineeDatabase
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream

//导入ZIP包
object ImportsUtils {

    //有效的ZIP文件目录
    private val DIRS = arrayOf(
        "student/",
        "student/student_images/",
        "student/student_violation_images/",
        "student/student_verification_images/"
    )

    private const val PLAN = "plan_info.txt"

    //查看dir路径是否包含需要的数据
    private fun hasContainsDir(dirPath: String): String? {
        for (dir in DIRS) {
            if (dirPath.endsWith(dir)) return dir
        }
        return null
    }

    //判断文件路径是否包含
    private fun hasContainsDirFile(path: String): String? {
        val index = path.lastIndexOf('/') + 1
        if (index in 1 until path.length) {
            val parentPath = path.substring(0, index)
            for (dir in DIRS) {
                if (parentPath.endsWith(dir)) {
                    return path.substring(index - dir.length)
                }
            }
        }
        return null
    }

    //导入USB ZIP文件
    fun importsZip(usbFile: UsbFile, dir: File): ExamPlan? {
        FileUtils.deleteFiles(dir)
        ExamineeDatabase.get().clearAll()
        val unzipSuccess = try {
            UsbFileInputStream(usbFile).use { fis ->
                unzipInputStream(fis, dir)
            }
            true
        } catch (e: Exception) {
            FileUtils.deleteFiles(dir)
            false
        }
        if (unzipSuccess) {
            val examPlan = importsExamPlan()
            val students = importsStudentList()
            if (examPlan != null && students != null) {
                examPlan.isNotEmpty()
                insertExamineeAndProjectList(examPlan, students)
            }
            return examPlan
        }
        return null
    }

    //导入ZIP文件
    fun importsZip(zipFile: File, dir: File): ExamPlan? {
        FileUtils.deleteFiles(dir)
        Glide.get(APP).clearDiskCache()
        ExamineeDatabase.get().clearAll()
        val unzipSuccess = try {
            FileInputStream(zipFile).use { fis ->
                unzipInputStream(fis, dir)
            }
            true
        } catch (e: Exception) {
            FileUtils.deleteFiles(dir)
            zipFile.delete()
            false
        }
        if (unzipSuccess) {
            val examPlan = importsExamPlan()
            val students = importsStudentList()
            if (examPlan != null && students != null) {
                examPlan.isNotEmpty()
                insertExamineeAndProjectList(examPlan, students)
            }
            return examPlan
        }
        return null
    }

    //考试计划
    fun importsExamPlan(): ExamPlan? {
        val jsonStr = UploadUtils.readTxtFile(UploadUtils.examineePlanPath())
        if (!TextUtils.isEmpty(jsonStr)) {
            return jsonStr!!.jsonToBean<ExamPlan>()
        }
        return null
    }

    //考生信息列表
    private fun importsStudentList(): List<Examinee>? {
        val jsonStr = UploadUtils.readTxtFile(UploadUtils.examineeInfoPath())
        if (!TextUtils.isEmpty(jsonStr)) {
            return jsonStr!!.jsonToList()
        }
        return null
    }

    //考生与项目中间表
    private fun insertExamineeAndProjectList(examPlan: ExamPlan, examineeList: List<Examinee>) {
        if (examineeList.isNotEmpty()) ExamineeDatabase.get().insertExaminee(examineeList)
        val examResults = ArrayList<ExamResult>()
        examineeList.forEach { examinee ->
            examinee.examProjectList?.forEach { projectId ->
                examPlan.examProject(projectId)?.also { examResults.add(ExamResult(examinee, it)) }
            }
        }
//        LogUtils.i("examineeList ${examResults.size} = $examResults")
        if (examineeList.isNotEmpty()) ExamineeDatabase.get().insertExamResult(examResults)
    }

    //解压ZIP
    private fun unzipInputStream(inputStream: InputStream, dir: File) {
        ZipInputStream(inputStream).use { zis ->
            var entry: ZipEntry?
            val buffer = ByteArray(1024)
            while (zis.nextEntry.also { entry = it } != null) {
                if (entry!!.isDirectory) {
                    hasContainsDir(entry!!.name)?.also { mkdir ->
                        File(dir, mkdir).takeIf { !it.exists() }?.mkdirs()
                    }
                } else {
                    if (entry!!.name.endsWith(PLAN)) {
                        unzipFile(File(dir, PLAN), zis, buffer)
                    } else {
                        hasContainsDirFile(entry!!.name)?.also {
                            unzipFile(File(dir, it), zis, buffer)
                        }
                    }
                }
            }
        }
    }

    //解压文件
    private fun unzipFile(file: File, zis: ZipInputStream, buffer: ByteArray): Boolean = try {
        FileOutputStream(file).use { fos ->
            var length: Int
            while (zis.read(buffer).also { length = it } > 0) {
                fos.write(buffer, 0, length)
            }
        }
        true
    } catch (_: Exception) {
        false
    }

    //添加压缩文件
    fun zipFile(fileList: List<File>, zipFile: File,  dir: String): Boolean {
        try {
            FileOutputStream(zipFile).use { os ->
                ZipOutputStream(os).use { zos ->
                    val bytes = ByteArray(1024)
                    fileList.forEach { file ->
                        val zipEntry = ZipEntry("$dir/${file.name}")
                        FileInputStream(file).use { input ->
                            zos.putNextEntry(zipEntry)
                            var length: Int
                            while (input.read(bytes).also { length = it } >= 0) {
                                zos.write(bytes, 0, length)
                            }
                            zos.closeEntry()
                        }
                    }
                }
            }
            return true
        } catch (_: Exception) {
            return false
        }
    }
}